package cn.hiapi.shopkeeper.service.activity;

import cn.hiapi.basic.entity.BasicEntity;
import cn.hiapi.basic.jpa.BasicRepository;
import cn.hiapi.basic.jpa.pageable.QueryWrapper;
import cn.hiapi.basic.service.AbsBasicService;
import cn.hiapi.basic.token.Token;
import cn.hiapi.basic.token.enums.TokenType;
import cn.hiapi.interfaces.DispatchContext;
import cn.hiapi.interfaces.finance.IAmountService;
import cn.hiapi.interfaces.finance.IAssetsService;
import cn.hiapi.interfaces.finance.model.AmountChange;
import cn.hiapi.interfaces.finance.model.AmountModel;
import cn.hiapi.shopkeeper.consts.AppConst;
import cn.hiapi.shopkeeper.entity.activity.Activity;
import cn.hiapi.shopkeeper.entity.activity.ActivityExpand;
import cn.hiapi.shopkeeper.entity.activity.ActivityOther;
import cn.hiapi.shopkeeper.entity.order.ActivityInviteRecord;
import cn.hiapi.shopkeeper.entity.order.ActivityOrder;
import cn.hiapi.shopkeeper.enums.ActivityType;
import cn.hiapi.shopkeeper.request.CreateOrderRequest;
import cn.hiapi.shopkeeper.service.Shopkeeper;
import cn.hiapi.shopkeeper.service.order.ActivityInviteRecordService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/**
 * @author AdinZ
 * @date 2022/12/13 0:50
 */
@Slf4j
public abstract class AbsActivityService<Repository extends BasicRepository<T, ID>, T extends BasicEntity, ID extends Serializable> extends AbsBasicService<Repository, T, ID> {
    protected final DispatchContext dispatchContext;

    protected AbsActivityService(DispatchContext dispatchContext) {
        this.dispatchContext = dispatchContext;
    }

    public T getByAid(long aid) {
        List<T> list = this.findList(new QueryWrapper().eq("aid", aid));
        if (list.isEmpty()) return null;
        return list.get(0);
    }


    public abstract ActivityType getActivityType();


    public abstract BasicEntity saveExpand(long aid, JSONObject data);


    public abstract int deleteByAid(long aid);

    /**
     * 邀请新用户,活动奖励
     *
     * @param record
     * @param other
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void inviteNewUser(ActivityInviteRecord record, ActivityOther other) {

        if (other == null) {
            record.setRemark("没有分享资料");
            return;
        }
        if (other.getShare() != 1) {
            record.setRemark("分享状态没开");
            return;
        }
        if (other.getShareAmount() == null || other.getShareAmount().compareTo(BigDecimal.ZERO) <= 0) {
            record.setRemark("邀请奖励金额没有");
            return;
        }

        if (other.getShareTotal() > 0) {
            long totalShare = this.dispatchContext.getServiceOne(ActivityInviteRecordService.class).count(new QueryWrapper().eq("aid", record.getAid()));

            if (totalShare >= other.getShareTotal()) {
                record.setRemark("超出总分享人数" + other.getShareTotal() + "/" + totalShare);
                return;
            }
        }
        AmountModel amountModel = this.dispatchContext.getServiceOne(IAmountService.class).getByFid(record.getShopId(), AppConst.FINANCE_AMOUNT_MONEY);
        if (amountModel == null || amountModel.getAmount().compareTo(other.getShareAmount()) < 0) {
            log.info("[邀请奖励] 分享邀请奖励,商家余额不足");
            record.setRemark("商家没有余额了");
            return;
        }
        //店铺支出
        this.dispatchContext.getServiceOne(IAssetsService.class).changeAmount(AmountChange.builder()
                .fid(record.getShopId()).fidType(AppConst.FID_TYPE_SHOP)
                .title("分享奖励支出").remark("分享奖励")
                .sourceId(record.getId()).sourceType(AppConst.FINANCE_INCOME_SOURCE_INVITE_COMMISSION)
                .amount(other.getShareAmount().negate()).type(AppConst.FINANCE_AMOUNT_MONEY)
                .mid(0)
                .build());
        //邀请人,收入
        this.dispatchContext.getServiceOne(IAssetsService.class).changeAmount(AmountChange.builder()
                .fid(record.getInviteUid()).fidType(TokenType.ROLE_USER)
                .title("分享奖励收入").remark("分享奖励")
                .sourceId(record.getId()).sourceType(AppConst.FINANCE_INCOME_SOURCE_INVITE_COMMISSION)
                .amount(other.getShareAmount()).type(AppConst.FINANCE_AMOUNT_MONEY)
                .mid(0)
                .build());
        record.setShareAward(1);
        record.setShareAmount(other.getShareAmount());
    }

    public abstract ActivityOrder createOrder(BasicEntity basic, Activity activity, Map<String, Long> incrementStock, CreateOrderRequest request, Token<Object> token);

    /**
     * 获取宽展详情
     *
     * @param aid
     * @return
     */
    public JSONObject getExpand(long aid) {
        T t = this.getByAid(aid);
        if (t == null) return null;
        JSONObject data = JSON.parseObject(t.toJSONString());
        return data;
    }

    /**
     * 计算 喜糖抵扣金额,
     * 不能高于活动价格
     *
     * @param activity 活动详情
     * @param rate     抵扣比例
     * @param amount   喜糖总量
     * @return 最大可抵扣的喜糖数量
     */
    public BigDecimal sugarDeduction(Activity activity, BigDecimal rate, BigDecimal amount, long uid) {
        if (amount.compareTo(BigDecimal.ZERO) <= 0) return BigDecimal.ZERO;
        //最大抵扣系统, 大于余额
        BigDecimal money = Shopkeeper.sugarToMoney(amount, rate);
        if (money.compareTo(activity.getPrice()) > 0) {
            //抵扣金额超过 活动金额了
            return Shopkeeper.moneyToSugar(activity.getPrice().subtract(BigDecimal.valueOf(0.1)), rate);
        }
        return amount;
    }

    protected BigDecimal sugarDeduction(BigDecimal price, BigDecimal rate, BigDecimal amount) {
        if (price == null || price.compareTo(BigDecimal.ZERO) <= 0) return BigDecimal.ZERO;
        BigDecimal money = Shopkeeper.sugarToMoney(amount, rate);
        if (money.compareTo(price) > 0) {
            //抵扣金额超过 活动金额了
            return Shopkeeper.moneyToSugar(price.subtract(BigDecimal.valueOf(0.1)), rate);
        }
        return amount;
    }

}
